<?php
class CC_FlagFlippers_Manager
{
    public static $indexKey = 'FlagFlippers';
    protected static $_guestsAllowedResources = array(
        'backoffice-users' => array('login')
    );
    
	/**
     * Load the ACL to the Registry if is not there
     * 
     * This function takes care about generating the acl from the db
     * if the info is not in the registry and/or APC.
     * 
     * If the acl is inside APC we load it from there.
     * 
     * @return void
     */
    public static function load()
    {
        if(!CC_FlagFlippers_Manager::_checkIfExist())
        {
            if(!$acl = CC_FlagFlippers_Manager::_getFromApc())
            {
                $acl = CC_FlagFlippers_Manager::_generateFromDb();
                CC_FlagFlippers_Manager::_storeInApc($acl);
            }
            
            CC_FlagFlippers_Manager::_storeInRegistry($acl);
        }
    }
    
    /**
     * Regenerate the Acl from the DB and update APC and Zend_Registry
     *
     * @return boolean
     */
    public static function save()
    {
        $acl = CC_FlagFlippers_Manager::_generateFromDb();
        CC_FlagFlippers_Manager::_storeInApc($acl);
        CC_FlagFlippers_Manager::_storeInRegistry($acl);
    }
    
    /**
     * Check if a role is allowed for a certain resource
     *
     * @param string $role 
     * @param string $resource 
     * @return boolean
     */
    public function isAllowed($role = NULL, $resource = NULL, $action = NULL)
    {
        if(empty($role))
        {
            $role = Zend_Auth::getInstance()->getIdentity();
        }
        
        if(!empty($resource))
        {
            $resource = strtolower(CURRENT_MODULE) . '-' . $resource;
        }
        
        if(!empty($action))
        {
            $action = CC_Inflector::camelCaseToDash($action);
        }
        
        return CC_FlagFlippers_Manager::_getFromRegistry()->isAllowed($role, $resource, $action);
    }
    
    /**
     * Log a message related to Flag And Flippers
     *
     * @param string $msg 
     * @param string $level 
     * @return void
     */
    public static function log($msg, $level = Zend_Log::INFO)
    {
        
    }
    
    /**
     * Check if the acl exists in Zend_Registry
     *
     * @return boolean
     */
    private function _checkIfExist()
    {
        return Zend_Registry::isRegistered(CC_FlagFlippers_Manager::$indexKey);
    }
    
    /**
     * Get Acl from Registry
     *
     * @return void
     */
    private static function _getFromRegistry()
    {
        if(CC_FlagFlippers_Manager::_checkIfExist())
        {
            return Zend_Registry::get(CC_FlagFlippers_Manager::$indexKey);
        }
        
        return false;
    }
    
    /**
     * Retrieve the acl from APC
     *
     * @return Zend_Acl | boolean
     */
    private static function _getFromApc()
    {
        
    }
    
    /**
     * Generate the Acl object from the permission file
     * @TODO: Change back to private method
     * @return Zend_Acl
     */
    public static function _generateFromDb()
    {
        /** @var Doctrine\ORM\EntityManager */
        $em = Zend_Registry::get('doctrine')->getEntityManager();
        
        $aclObject = new Zend_Acl();
        $aclObject->deny(); // Start by denying access to everything
        
        // Get all entites
        $groupsArray = $em->getRepository('CC\Entity\Group')->findAll();
        $flagsArray = $em->getRepository('CC\Entity\Flag')->findAll();
        $flippersArray = $em->getRepository('CC\Entity\Flipper')->findAll();
        $privilegeModel = $em->getRepository('CC\Entity\Privilege')->findAll();
        
        // Add all groups
        foreach($groupsArray as $group)
        {
            if($group->getParent() !== null)
                $aclObject->addRole(new Zend_Acl_Role($group->getName(), $group->getParent()->getName()));
            else
                $aclObject->addRole(new Zend_Acl_Role($group->getName()));
        }
        
        // Add all users
        $usersArray = $em->getRepository('CC\Entity\User')->findAll();
        foreach($usersArray as $user)
        {
            $usersGroups = $user->getGroups();
            
            foreach($usersGroups as $group)
                $userGroupArray[] = $group->getName();
            
            $aclObject->addRole(new Zend_Acl_Role($user->getEmail()), $userGroupArray);
        }
        
        // Add all resources
        foreach($flagsArray as $flag)
        {
            $aclObject->addResource(new Zend_Acl_Resource($flag->getName()));
        }
        
        // Add hardcoded resources
        $aclObject->addResource('frontend-error');
        $aclObject->addResource('backoffice-error');
        
        // Populate the ACLs
        foreach($flippersArray as $flipper)
        {
            switch(APPLICATION_ENV)
            {
                case 'production':
                    $envAllowed = $flipper->getFlag()->isActiveOnProduction();
                    break;
                default:
                    $envAllowed = $flipper->getFlag()->isActiveOnDev();
            }
            
            if($flipper->isAllow() && $envAllowed)
            {
                $aclObject->allow($flipper->getGroup()->getName(),
                                  $flipper->getFlag()->getName(),
                                  $flipper->getPrivilege()->getName());
            }
            else
            {
                $aclObject->deny($flipper->getGroup()->getName(),
                                 $flipper->getFlag()->getName(),
                                 $flipper->getPrivilege()->getName());
            }
        }
        
        // Hardcode basic paths for guests
        // @TODO: Have acl manage everything
        foreach(CC_FlagFlippers_Manager::$_guestsAllowedResources as $resource => $roles)
        {
            if(!is_array($roles))
            {
                $aclObject->allow('guests', $resource);
            }
            else 
            {
                foreach($roles as $role)
                {
                    $aclObject->allow('guests', $resource, $role);
                }
            }
        }
        
        // Everybody can see the errors
        $aclObject->allow(null, 'frontend-error');
        $aclObject->allow(null, 'backoffice-error');
        
        // Developers are allowed everywhere
        $aclObject->allow('administrators');
        
        return $aclObject;
        
        
    }
    
    /**
     * Store the Acl in APC
     *
     * @return void
     */
    private static function _storeInApc($acl = NULL)
    {
        
    }
    
    /**
     * Store the Acl in the Registry
     *
     * @return void
     */
    private static function _storeInRegistry($acl)
    {
        Zend_Registry::set(CC_FlagFlippers_Manager::$indexKey, $acl);
    }
}
?>